package com.spbdx.common.utils.http;

import cn.hutool.core.util.StrUtil;
import okhttp3.*;

import javax.net.ssl.*;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 通用http发送方法
 *
 * @author cms
 */
public class HttpUtils {
    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    /**
     * 线程池数量：100
     */
    public static final String MAX_IDLE_CONNECTION = "100";

    /**
     * 连接超时：45000ms
     */
    public static final String CINNETC_TIMEOUT = "45000";

    /**
     * 读超时：45000ms
     */
    public static final String READ_TIMEOUT = "45000";

    /**
     * 保存长连接时间：1min
     */
    public static final String KEEP_ALIVE_DURATION = "1";

    private static OkHttpClient httpClient;

    private static OkHttpClient httpsClient;

    static {
        httpClient = new OkHttpClient.Builder()
//            .sslSocketFactory(OkHttpUtil.getIgnoreInitedSslContext().getSocketFactory(), OkHttpUtil.IGNORE_SSL_TRUST_MANAGER_X509)
//            .hostnameVerifier(OkHttpUtil.getIgnoreSslHostnameVerifier())
                .connectTimeout(Long.valueOf(CINNETC_TIMEOUT), TimeUnit.MILLISECONDS)
                .readTimeout(Long.valueOf(READ_TIMEOUT), TimeUnit.MILLISECONDS)
                .connectionPool(new ConnectionPool(Integer.valueOf(MAX_IDLE_CONNECTION), Long.valueOf(KEEP_ALIVE_DURATION), TimeUnit.MINUTES)).build();
    }

    static {
        httpsClient = getUnsafeOkHttpClient();
    }
    /**
     * 向指定 URL 发送GET方法的请求 参数 url后面直接跟上参数，如：http://www.baidu.com?name=123&age=456 这种形式的参数传递方式
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, Map<String, String> headers) {
        String result = "";
        try {
            String urlNameString = url + "?" + param;
            URL realUrl = new URL(urlNameString);
            // 创建request
            Request.Builder reqBuilder = new Request.Builder();
            // 加入header参数
            addHeaders(reqBuilder, headers);
            Request request = reqBuilder
                    .url(realUrl)
                    .header("accept", "*/*")
                    .header("connection", "Keep-Alive")
                    .header("user-agent", "ehome-push")
                    .build();

            Response response = getHttpClient(url).newCall(request).execute();
            result = response.body().string();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求 参数 url后面直接跟上参数， application/x-www-form-urlencoded
     *
     * @param url    发送请求的 URL
     * @param params 请求参数，请求参数应该是 application/x-www-form-urlencoded 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPostForm(String url, Map<String, Object> params, Map<String, String> headers) {
        String result = "";
        try {
            // 创建request
            Request.Builder reqBuilder = new Request.Builder();
            // 加入header参数
            addHeaders(reqBuilder, headers);
            // 创建请求body
            RequestBody body = genFromRequestBody(params);
            URL realUrl = new URL(url);
            Request request = reqBuilder.url(realUrl).post(body).build();
            System.out.printf("请求前,url:%s, form:%s%n", url, params);
            Response response = getHttpClient(url).newCall(request).execute();

            result = response.body().string();
            System.out.printf("请求后,result:%s%n", result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 向指定 URL 发送POST方法的请求，请求体为json格式
     *
     * @param url
     * @param jsonString
     * @param headers
     * @return
     */
    public static String sendPostJson(String url, String jsonString, Map<String, String> headers) {
        String result = "";
        try {
            // 创建request
            Request.Builder reqBuilder = new Request.Builder();
            // 加入header参数
            addHeaders(reqBuilder, headers);
            // 创建请求body
            RequestBody body = genJsonRequestBody(jsonString);
            URL realUrl = new URL(url);
            Request request = reqBuilder.url(realUrl).post(body).build();
            System.out.printf("请求前,url:%s, json:%s%n", url, jsonString);
            Response response = getHttpClient(url).newCall(request).execute();

            result = response.body().string();
            System.out.printf("请求后,result:%s%n", result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    private static void addHeaders(Request.Builder reqBuilder, Map<String, String> headers) {
        // 配置header
        reqBuilder.addHeader("accept", "*/*");
        reqBuilder.addHeader("connection", "Keep-Alive");
        if (headers != null) {
            headers.forEach(reqBuilder::addHeader);
        }
    }


    /**
     * 创建一个表单编码的请求体（application/x-www-form-urlencoded）
     *
     * @param params
     * @return
     */
    private static RequestBody genFromRequestBody(Map<String, Object> params) {
        // 组装入参
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {
            params.forEach((key, val) -> builder.add(key, String.valueOf(val)));
        }
        return builder.build();
    }

    /**
     * 创建一个json格式的请求体（application/json）
     *
     * @param jsonString
     * @return
     */
    public static RequestBody genJsonRequestBody(String jsonString) {
        if (jsonString == null) {
            return null;
        }
        return RequestBody.create(JSON, jsonString);
    }

    public static OkHttpClient getHttpClient(String url) {
        if (StrUtil.startWith(url, "https")) {
            return httpsClient;
        } else {
            return httpClient;
        }
    }

    /**
     * 获取OkHttpClient
     *
     * @return OkHttpClient
     */
    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[]{};
                }
            }};

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout(Long.valueOf(CINNETC_TIMEOUT), TimeUnit.MILLISECONDS).readTimeout(Long.valueOf(READ_TIMEOUT), TimeUnit.MILLISECONDS).connectionPool(new ConnectionPool(Integer.valueOf(MAX_IDLE_CONNECTION), Long.valueOf(KEEP_ALIVE_DURATION), TimeUnit.MINUTES)).build();
            // 过时方法，单构造参数方法过时，多传一个X509TrustManager就可以了
            //builder.sslSocketFactory(sslSocketFactory);
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}